package com.xjnt.frameworks.plugin.sql;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jfinal.log.Logger;
import com.xjnt.frameworks.plugin.sql.element.SqlGroup;
import com.xjnt.frameworks.plugin.sql.element.SqlItem;
import com.xjnt.frameworks.plugin.sql.element.SqlRoot;
import com.xjnt.frameworks.utils.JaxbKit;

public class SqlKit {

	protected static final Logger LOG = Logger.getLogger(SqlKit.class);

	private static Map<String, String> sqlMap;

	public static String findSql(String groupNameAndsqlId) {
		if (sqlMap == null) {
			throw new NullPointerException("SqlPlugin not start");
		}
		return sqlMap.get(groupNameAndsqlId);
	}

	static void clearSqlMap() {
		sqlMap.clear();
	}

	static void init() {
		sqlMap = Maps.newHashMap();
		// 加载sql文件
		Enumeration<URL> baseURLs = null;
		try {
			baseURLs = SqlKit.class.getClassLoader().getResources("sql");
			if (baseURLs == null) {
				baseURLs = SqlKit.class.getClassLoader().getResources("");
			}
			URL url = null;
			while (baseURLs.hasMoreElements()) {
				url = baseURLs.nextElement();
				loadFilePath(url);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		LOG.debug("sqlMap" + sqlMap);
	}

	private static void loadFilePath(URL baseURL) {
		if (baseURL != null) {
			String protocol = baseURL.getProtocol();
			String basePath = baseURL.getFile();
			if ("jar".equals(protocol)) {
				String[] pathurls = basePath.split("!/");
				// 获取jar
				try {
					loadJarFileList(URLDecoder.decode(pathurls[0].replace("file:", ""), "UTF-8"), pathurls[1]);
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				// 加载sql文件
				loadFileList(basePath);
			}
		}
	}

	public static void loadFileList(String strPath) {
		List<File> files = Lists.newArrayList();
		File dir = new File(strPath);
		File[] dirs = dir.listFiles(new FileFilter() {
			@Override
			public boolean accept(File pathname) {
				if (pathname.getName().endsWith("sql") || pathname.getName().endsWith("sql.xml")) {
					return true;
				}
				return false;
			}
		});

		if (dirs == null)
			return;
		for (int i = 0; i < dirs.length; i++) {
			if (dirs[i].isDirectory()) {
				loadFileList(dirs[i].getAbsolutePath());
			} else {
				if (dirs[i].getName().endsWith("sql.xml")) {
					files.add(dirs[i]);
				}
			}
		}
		// 加载sql文件
		loadFiles(files);
	}

	/**
	 * find jar file
	 *
	 * @param filePath
	 *            文件路径
	 * @param packageName
	 *            包名
	 * @return list
	 * @throws java.io.IOException
	 *             文件读取异常
	 */
	private static void loadJarFileList(String filePath, String packageName) throws IOException {
		Map<String, InputStream> sqlFiles = Maps.newHashMap();
		JarFile localJarFile = new JarFile(new File(filePath));
		sqlFiles = findInJar(localJarFile, packageName);
		// 加载sql文件
		loadStreamFiles(sqlFiles);
		localJarFile.close();
	}

	/**
	 * 从jar里加载文件
	 *
	 * @param localJarFile
	 *            文件路径
	 * @param packageName
	 *            包名
	 * @return
	 */
	private static Map<String, InputStream> findInJar(JarFile localJarFile, String packageName) {
		try {
			Map<String, InputStream> sqlFiles = Maps.newHashMap();
			Enumeration<JarEntry> entries = localJarFile.entries();
			while (entries.hasMoreElements()) {
				JarEntry jarEntry = entries.nextElement();
				String entryName = jarEntry.getName();
				if (!jarEntry.isDirectory() && (packageName == null || entryName.startsWith(packageName)) && entryName.endsWith("sql.xml")) {
					sqlFiles.put(entryName.substring(entryName.lastIndexOf("/") + 1), localJarFile.getInputStream(jarEntry));
				}
			}
			return sqlFiles;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 加载xml文件
	 *
	 * @param files
	 */
	private static void loadFiles(List<File> files) {
		for (File xmlfile : files) {
			SqlRoot root = JaxbKit.unmarshal(xmlfile, SqlRoot.class);
			for (SqlGroup sqlGroup : root.sqlGroups) {
				getSql(xmlfile.getName(), sqlGroup);
			}
		}
	}

	private static void loadStreamFiles(Map<String, InputStream> streams) {
		for (String filename : streams.keySet()) {
			SqlRoot root = JaxbKit.unmarshal(streams.get(filename), SqlRoot.class);
			for (SqlGroup sqlGroup : root.sqlGroups) {
				getSql(filename, sqlGroup);
			}
		}
	}

	private static void getSql(String filename, SqlGroup sqlGroup) {
		String name = sqlGroup.name;
		if (name == null || name.trim().equals("")) {
			name = filename;
		}
		for (SqlItem sqlItem : sqlGroup.sqlItems) {
			sqlMap.put(name + "." + sqlItem.id, sqlItem.value);
		}
	}
}
